import React from "react";
import BaseComp from "./BaseComp";
import PropTypes from "prop-types";
import {isObjectValEqual, isNotEmpty} from "jh-utils";
import {forEach, isBoolean, isFunction} from "lodash-es";

/**
 * 表单基础组件的基类
 */
export default class BaseField extends BaseComp {

    static propTypes = {
        ...BaseComp.propTypes,
        /**
         * 标识当前组件是否在“表格的单元格”使用
         */
        cell: PropTypes.bool,
        value: PropTypes.any,
        defaultValue: PropTypes.any,
        /**
         * （在表格中才有效）切换到上一单元格
         */
        prevFunc: PropTypes.func,
        /**
         * （在表格中才有效）切换到下一单元格
         */
        nextFunc: PropTypes.func,
    };

    static getDerivedStateFromProps(nextProps, preState) {

        // 有 value，说明这是个受控组件，则以 value 为准
        if ('value' in nextProps) {
            return {
                value: isNotEmpty(nextProps.value) ? nextProps.value : null,
                originValue: nextProps.value
            };

        } else if ('defaultValue' in nextProps && preState &&
            !isObjectValEqual({defaultValue: nextProps.defaultValue}, {defaultValue: preState.defaultValue})) {
            // 如果是作为非受控组件。当 defaultValue 改变，则更新组件内的数据
            return {
                value: isNotEmpty(nextProps.defaultValue) ? nextProps.defaultValue : null,
                originValue: nextProps.defaultValue,
                defaultValue: nextProps.defaultValue
            };
        }
        return null;
    }

    static fieldType = ''; // 当值等于'filter' 时，说明是作为筛选条件使用

    moreCommonProps() {
        return [...super.moreCommonProps(),
            'nextFunc', 'prevFunc',
            'fieldCtrl', 'compLabel', 'fieldName',
            'rowIndex', 'cell', 'record', 'dataIndex', 'colsConf', 'floatNum', 'format'
        ]
    }

    initState(props) {
        return {
            value: props.value || props.defaultValue || null,
            defaultValue: props.defaultValue,
            originValue: props.value
        }
    }

    /**
     * 设置组件的值
     * @param value
     * @param afterCb
     */
    setValue(value, afterCb) {
        this.setState({
            value,
            originValue: value
        }, () => {
            this.hdlValueChange(value);
            afterCb && afterCb()
        });
    }

    /**
     * 获取组件的值
     * @return {*}
     */
    getValue() {
        return this.state.value;
    }

    /**
     * 此组件节点的实例。通常是为了用来调用 this.nodeRef.focus() 等方法
     */
    nodeRef;

    /**
     * 聚焦组件
     */
    focus() {
        if (this.nodeRef && isFunction(this.nodeRef.focus)) {
            this.nodeRef.focus();
        }
    }

    /**
     * 值变化之后的回调方法数组。用于支持“需要相应多次回调事件”的情况
     * @type {[function(value)]}
     */
    editAfterCbs = [];

    /**
     * 组件编辑前（发请求之前）的回调方法数组。用于支持“需要相应多次回调事件”的情况
     * @type {[function(compIns)]}
     */
    editBeforeCbs = [];

    /**
     * 设置“组件的值-编辑前”事件处理。重复调用此方法，可实现“多次事件绑定”
     * @param cb {function(compIns: {})} // compIns 是当前编辑组件的实例
     */
    addEditBeforeHandler(cb) {
        if (isFunction(cb)) {
            this.editBeforeCbs.push(cb);
        }
    }

    /**
     * 设置“组件的值-编辑后”事件处理。重复调用此方法，可实现“多次事件绑定”
     * @param cb {function(value)}
     */
    addEditAfterHandler(cb) {
        if (isFunction(cb)) {
            this.editAfterCbs.push(cb);
        }
    }

    runBeforeCbs() {
        // console.log('runBeforeCbs', this.editBeforeCbs);
        forEach(this.editBeforeCbs, (cb) => {
            cb(this);
        });
    }

    runAfterCbs(value) {
        const needAfterCb = this.getPropsByName('needAfterCb');
        // 判读是否需要执行“明细页-字段值改变后的回调”
        if (false === needAfterCb) {
            return;
        }
        // console.log('runAfterCbs', this.editAfterCbs);
        forEach(this.editAfterCbs, (cb) => {
            cb(value, null, this.getPropsByName('fieldName'));
        });
    }

    hdlValueChange(value) {
        // console.log('hdlValueChange', value);
        this.runValueChange(value);
    }

    runValueChange(value) {

        // 作为受控组件
        if ('value' in this.props) {
            this._changeFunc(value);

        } else {
            this.setState({value}, () => {
                this._changeFunc(value);
            });
        }
    }

    _changeFunc(value) {
        this.runPropsFunc('onChange')(value);
        this.runAfterCbs(value);
    }
}